package com.gzsxy.esjy.service.core.util;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.UUID;
import com.google.common.collect.Lists;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.*;
import com.itextpdf.text.pdf.parser.ImageRenderInfo;
import com.itextpdf.text.pdf.parser.PdfReaderContentParser;
import com.itextpdf.text.pdf.parser.RenderListener;
import com.itextpdf.text.pdf.parser.TextRenderInfo;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.ImageType;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @author zhangxiaolong
 * @date 2022/7/13 11:36
 */
@Slf4j
public class PdfUtils {

    /**
     * A4高度
     */
    private final static float A4_HEIGHT = 842;
    /**
     * A4宽度
     */
    private final static float A4_WIDTH = 595;

    public static boolean image2PdfByBase64(File outFile, String imgBase64) {
        return image2PdfByBase64(outFile, Lists.newArrayList(imgBase64));
    }

    public static boolean image2PdfByBase64(File outFile, List<String> imgBase64List) {
        //进行文件的存储
        List<String> imgPathList = new ArrayList<>();
        imgBase64List.forEach(base64 -> {
            byte[] decode = Base64.decode(base64);
            String filePath = Paths.get("./temp/img2Pdf", UUID.randomUUID().toString() ).toString();
            FileUtil.writeBytes(decode, new File(filePath));
            imgPathList.add(filePath);
        });

        try {
            return image2PdfByPath(outFile, imgPathList);
        } finally {
            imgPathList.forEach(path -> {
                new File(path).delete();
            });
        }
    }

    /**
     * 图片合成PDf
     *
     * @param outFile 输出文件
     * @param imgPath 图片访问路径
     * @return true or false
     */
    public static boolean image2PdfByPath(File outFile, String imgPath) {
        return image2PdfByPath(outFile, Lists.newArrayList(imgPath));
    }

    /**
     * 图片合成PDf
     *
     * @param outFile     输出文件
     * @param imgPathList 图片访问路径列表
     * @return true or false
     */
    public static boolean image2PdfByPath(File outFile, List<String> imgPathList) {
        Document doc = null;
        try (FileOutputStream fos = new FileOutputStream(outFile)) {
            // 创建文档
            doc = new Document(PageSize.A4, 0, 0, 0, 0);
            // 写入PDF文档
            PdfWriter.getInstance(doc, fos);
            for (String imgPath : imgPathList) {
                doc.newPage();
                Image image = Image.getInstance(imgPath);
                image.scaleAbsolute(A4_WIDTH, A4_HEIGHT);
                // 添加图片到文档
                doc.open();
                doc.add(image);
            }
            doc.close();
        } catch (Exception e) {
            log.error("合成pdf失败", e);
            return false;
        }

        return true;
    }

    /**
     * 图片合成PDf
     *
     * @param picDataList 图片数据数组集合
     * @return true or false
     */
    public static byte[] image2PdfByPath(List<byte[]> picDataList) {
        Document doc = null;
        byte[] bytes;
        try (ByteArrayOutputStream buffer = new ByteArrayOutputStream()) {
            // 创建文档
            doc = new Document(PageSize.A4, 0, 0, 0, 0);
            // 写入PDF文档
            PdfWriter.getInstance(doc, buffer);
            // 打开文档
            doc.open();
            for (byte[] picData : picDataList) {
                Image image = Image.getInstance(picData);
                //image.scaleAbsolute(image.getWidth(), image.getHeight());
                // 图片居中
                image.setAlignment(Image.ALIGN_CENTER);
                float percent = getPercent(image.getHeight(), image.getWidth());
                image.setAlignment(Image.MIDDLE);
                image.scalePercent(percent);
                // 设置页面宽高与图片一致
                Rectangle rectangle = new Rectangle(image.getScaledWidth(), image.getScaledHeight());
                doc.setPageSize(rectangle);
                // 新建一页添加图片
                doc.newPage();
                doc.add(image);
            }
            doc.close();
            bytes = buffer.toByteArray();
            buffer.write(bytes);
            return bytes;
        } catch (Exception e) {
            log.error("合成pdf失败", e);
            throw new RuntimeException(e);
        }
    }

    /**
     * 等比压缩，获取压缩百分比
     *
     * @param height 图片的高度
     * @param weight 图片的宽度
     * @return 压缩百分比
     */
    private static float getPercent(float height, float weight) {
        float percentHeight = 0.0F;
        float percentWeight = 0.0F;
        percentHeight = PageSize.A4.getHeight() / height * 100;
        percentWeight = PageSize.A4.getWidth() / weight * 100;
        //对比获取压缩比例更大的哪一个，防止越界出A4纸的比例
        if (percentHeight > percentWeight){
            return percentWeight;
        }
        return percentHeight;
    }

    /**
     * 添加水印文字
     *
     * @param inputFile   输入文件
     * @param outFile     输出文件
     * @param pdfMarkList 水印坐标列表
     * @return true or flase
     */
    public static boolean addPdfMark(File inputFile, File outFile, List<PdfMark> pdfMarkList) {
        try (InputStream inputStream = new FileInputStream(inputFile);
             OutputStream outputStream = new FileOutputStream(outFile)
        ) {
            return addPdfMark(inputStream, outputStream, pdfMarkList);
        } catch (Exception e) {
            log.error("pdf添加水印失败:{}", e.getMessage());
            return false;
        }
    }

    /**
     * 添加水印
     *
     * @param inputFile   pdf源文件
     * @param outFile     输出文件
     * @param pdfMarkList 水印内容列表
     */
    public static boolean addPdfMark(InputStream inputFile, OutputStream outFile, List<PdfMark> pdfMarkList) {
        PdfReader reader = null;
        PdfStamper stamp = null;
        try {
//            BaseFont base = BaseFont.createFont("/fonts/simsun.ttc,0", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
            ////创建中文的文字字体，自定义字体文件
            BaseFont base = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
            // 设置水印透明度
            PdfGState gs = new PdfGState();
            // 设置填充字体不透明度为0.4f
            gs.setFillOpacity(0.4f);

            //content = stamper.getOverContent(i);// 在内容上方加水印
            // content = stamper.getUnderContent(i);//在内容下方加水印

            reader = new PdfReader(inputFile);

            //先查找关键字位置
            PdfReader finalReader = reader;
            Font font = new Font(base, 12, Font.NORMAL);

            stamp = new PdfStamper(reader, outFile);
            int pages = reader.getNumberOfPages();
            for (PdfMark m : pdfMarkList) {
//                getKeyWords(m.getPdfPage(), finalReader, "看守所");
                //大于总页数
                Integer page = m.getPdfPage();
                if (pages < page) {
                    return false;
                }

                PdfContentByte under = stamp.getUnderContent(page);
                if (1 == m.getType()) {
                    //图片类型
                    Image img = null;
                    try {
                        img = Image.getInstance(m.getContent());
                        //缩放
//                        img.scaleToFit(100, 100);

                        float imgHeight = img.getHeight() / 2;

                        img.setAbsolutePosition(m.getX(), m.getY());
                        under.addImage(img);
                    } catch (Exception e) {
                        log.error("e", e);
                        return false;
                    }
                } else if (2 == m.getType() || 3 == m.getType()) {
                    ////设置文字的大小
                    under.setFontAndSize(font.getCalculatedBaseFont(true), font.getCalculatedSize());
                    under.beginText();
                    ////设置文字内容
                    under.showTextAligned(Element.ALIGN_CENTER, m.getContent(), m.getX(), m.getY(), 0);
                    under.endText();
                }
            }
            return true;
        } catch (Exception e) {
            log.error("addPdfMark:", e);
            return false;
        } finally {
            try {
                if (null != stamp) {
                    stamp.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            if (null != reader) {
                reader.close();
            }
        }
    }

    /**
     * 在顶层添加水印文字
     *
     * @param inputFile   输入文件
     * @param outFile     输出文件
     * @param pdfMarkList 水印坐标列表
     * @param fontSize 字体大小
     * @param fontPosition 字体位置  ALIGN_LEFT = 0,ALIGN_CENTER = 1,ALIGN_RIGHT = 2
     * @return true or flase
     */
    public static boolean addPdfMarkOnTop(File inputFile, File outFile, List<PdfMark> pdfMarkList, Integer fontSize, Integer fontPosition) {
        try (InputStream inputStream = new FileInputStream(inputFile);
             OutputStream outputStream = new FileOutputStream(outFile)
        ) {
            return addPdfMarkOnTop(inputStream, outputStream, pdfMarkList, fontSize, fontPosition);
        } catch (Exception e) {
            log.error("pdf添加水印失败:{}", e.getMessage());
            return false;
        }
    }


    /**
     * 在顶层添加水印
     *
     * @param inputFile   pdf源文件
     * @param outFile     输出文件
     * @param pdfMarkList 水印内容列表
     * @param fontSize 字体大小
     * @param fontPosition 字体位置  ALIGN_LEFT = 0,ALIGN_CENTER = 1,ALIGN_RIGHT = 2
     */
    public static boolean addPdfMarkOnTop(InputStream inputFile, OutputStream outFile, List<PdfMark> pdfMarkList, Integer fontSize, Integer fontPosition) {
        PdfReader reader = null;
        PdfStamper stamp = null;
        try {
            Resource resource = null;
            String absolutePath = null;
            ResourcePatternResolver resourceLoader = new PathMatchingResourcePatternResolver();
            try {
                resource = resourceLoader.getResource("classpath:fonts/simsun.ttf");
                absolutePath = resource.getFile().getAbsolutePath();
            } catch (IOException e) {
                log.error(e.getMessage());
            }
            File f = new File(absolutePath);
            if(!f.exists()){
                absolutePath = "/fonts/simsun.ttf";
            }
            BaseFont base = BaseFont.createFont(absolutePath, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
            // 设置水印透明度
            PdfGState gs = new PdfGState();
            // 设置填充字体不透明度为0.4f
            gs.setFillOpacity(0.4f);

            reader = new PdfReader(inputFile);

            //先查找关键字位置
            PdfReader finalReader = reader;
            Font font = new Font(base, fontSize, Font.NORMAL);

            stamp = new PdfStamper(reader, outFile);
            int pages = reader.getNumberOfPages();
            for (PdfMark m : pdfMarkList) {
//                getKeyWords(m.getPdfPage(), finalReader, "看守所");
                //大于总页数
                Integer page = m.getPdfPage();
                if (pages < page) {
                    return false;
                }

                PdfContentByte over = stamp.getOverContent(page);
                if (1 == m.getType()) {
                    //图片类型
                    Image img = null;
                    try {
                        img = Image.getInstance(m.getContent());

                        img.setAbsolutePosition(m.getX(), m.getY());
                        over.addImage(img);
                    } catch (Exception e) {
                        log.error("e", e);
                        return false;
                    }
                } else if (2 == m.getType() || 3 == m.getType()) {
                    over.setFontAndSize(font.getCalculatedBaseFont(true), font.getCalculatedSize());
                    over.beginText();
                    over.showTextAligned(fontPosition, m.getContent(), m.getX(), m.getY(), 0);
                    over.endText();
                }
            }
            return true;
        } catch (Exception e) {
            log.error("addPdfMarkOnTop:", e);
            return false;
        } finally {
            try {
                if (null != stamp) {
                    stamp.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            if (null != reader) {
                reader.close();
            }
        }
    }

    private static void getKeyWords(int page, PdfReader pdfReader, String keyword) {
        try {
            PdfReaderContentParser pdfReaderContentParser = new PdfReaderContentParser(pdfReader);
            pdfReaderContentParser.processContent(page, new RenderListener() {
                @Override
                public void beginTextBlock() {
                }

                @Override
                public void renderText(TextRenderInfo renderInfo) {
                    String text = renderInfo.getText();
                    // 判断是否匹配上
                    if (text.contains(keyword)) {

                        // 计算中心点坐标

                        com.itextpdf.awt.geom.Rectangle2D.Float baseFloat = renderInfo.getBaseline()
                                .getBoundingRectange();
                        com.itextpdf.awt.geom.Rectangle2D.Float ascentFloat = renderInfo.getAscentLine()
                                .getBoundingRectange();
                        System.out.println("X" + baseFloat.x);
                        System.out.println("Y" + baseFloat.y);
                    }
                }

                @Override
                public void endTextBlock() {

                }

                @Override
                public void renderImage(ImageRenderInfo renderInfo) {

                }
            });
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        }
    }

    public static void main(String[] args) throws Exception {
//        String string = FileUtil.readString("D:\\Gosun\\IVMP\\trunk\\source\\code\\WebServer\\ivmp-admin\\server\\arraign-server\\src\\main\\resources\\config\\pdfConfig.json", "utf-8");
//        List<PdfConfigDto> parse = JSON.parseObject(string, new TypeReference<List<PdfConfigDto>>(){});


//        InputStream inputStream = new FileInputStream(new File("D:\\文书模板\\test\\提讯提解证-厦门.pdf"));
//        OutputStream outputStream = new FileOutputStream(new File("D:\\文书模板\\test\\提讯提解证-厦门test.pdf"));
//
        //InputStream inputStream = new FileInputStream(new File("D:\\文书模板\\test\\逮捕证.PDF"));
        //OutputStream outputStream = new FileOutputStream(new File("D:\\文书模板\\test\\逮捕证-test.PDF"));

//        InputStream inputStream = new FileInputStream(new File("D:\\文书模板\\test\\11.pdf"));
//        OutputStream outputStream = new FileOutputStream(new File("D:\\文书模板\\test\\11-test.PDF"));

//        InputStream inputStream = new FileInputStream(new File("D:\\文书模板\\test\\变更羁押期限通知书.PDF"));
//        OutputStream outputStream = new FileOutputStream(new File("D:\\文书模板\\test\\变更羁押期限通知书-test.PDF"));
//
//        InputStream inputStream = new FileInputStream(new File("D:\\文书模板\\test\\鉴定意见通知书.PDF"));
//        OutputStream outputStream = new FileOutputStream(new File("D:\\文书模板\\test\\鉴定意见通知书-test.PDF"));
//
//
////        621: {"x":353, "y":116,"type":2, "page":2, "keyWord":"年"}
////        622: {"x":400, "y":116,"type":2, "page":2, "keyWord":"月"}
////        623: {"x":440, "y":116,"type":2, "page":2, "keyWord":"日"}
//
        List<PdfMark> list = new ArrayList();
        PdfMark pdfMark = new PdfMark();


        //字符串
//        pdfMark.setType(2);
//
//        pdfMark.setContent("张三丰");
//        pdfMark.setX(205);
//        pdfMark.setY(160);
//        pdfMark.setPdfPage(1);

        //年月日
        pdfMark.setType(2);
//        pdfMark.setContent(DateUtil.format(new Date(), "yyyy-MM-dd"));
        pdfMark.setContent("张三丰");
        pdfMark.setX(205);
        pdfMark.setY(125);
        pdfMark.setPdfPage(2);

//        PdfMark pdfMark2 = new PdfMark();
//        pdfMark2.setType(2);
//        pdfMark2.setContent("14:00:53");
//        //pdfMark.setContent("T_X_10059");
//        pdfMark2.setX(490F);
//        pdfMark2.setY(689F);
//        pdfMark2.setPdfPage(2);
//        list.add(pdfMark2);
//        //盖章
//        pdfMark.setType(2);
//        pdfMark.setContent("C:\\Users\\zengjinjian\\Desktop\\盖章.png");
//        pdfMark.setX(800);
//        pdfMark.setY(692);
//        pdfMark.setPdfPage(1);



//        PdfMark pdfMarkMonth = new PdfMark();
//        BeanUtil.copyProperties(pdfMark, pdfMarkMonth);
//        pdfMarkMonth.setX(pdfMarkMonth.getX()+28);
//        pdfMarkMonth.setContent(DateUtil.format(new Date(), "MM"));
//        list.add(pdfMarkMonth);
//
//        PdfMark pdfMarkDay = new PdfMark();
//        BeanUtil.copyProperties(pdfMark, pdfMarkDay);
//        pdfMarkDay.setX(pdfMarkDay.getX()+53);
//        pdfMarkDay.setContent(DateUtil.format(new Date(), "dd"));
//        list.add(pdfMarkDay);
//
//        //时分
//        PdfMark pdfMarkHour = new PdfMark();
//        BeanUtil.copyProperties(pdfMark, pdfMarkHour);
//        pdfMarkHour.setX(pdfMarkHour.getX()+78);
//        pdfMarkHour.setContent(DateUtil.format(new Date(), "HH"));
//        list.add(pdfMarkHour);
//        PdfMark pdfMarkMin = new PdfMark();
//        BeanUtil.copyProperties(pdfMark, pdfMarkMin);
//        pdfMarkMin.setX(pdfMarkMin.getX()+103);
//        pdfMarkMin.setContent(DateUtil.format(new Date(), "mm"));
//        list.add(pdfMarkMin);

        list.add(pdfMark);

        String input = "E:\\Desktop\\文书盖章\\重庆文书\\逮捕证.pdf";
        String output = "E:\\Desktop\\文书盖章\\重庆文书\\逮捕证1.pdf";
        InputStream inputStream = new FileInputStream(input);
        OutputStream outputStream = new FileOutputStream(output);
        addPdfMark(inputStream, outputStream, list);

        DateTime dateTime = DateUtil.parseDate("2022-02-24 14:29:30");
        String format = DateUtil.format(dateTime, "yyyy-MM-dd");
        System.out.println(format);

//        image2PdfByBase64(new File("D:\\文书模板\\img2pdf.pdf"), Lists.newArrayList(Base64.encode(new File("D:\\文书模板\\2.png")), Base64.encode(new File("D:\\文书模板\\1.png"))));


    }

    @Getter
    @Setter
    public static class PdfMark {
        /**
         * 水印类型 1.图片 2.日期（偏移）
         */
        private Integer type;

        private float x;
        private float y;
        /**
         * 如为图片:则这个为图片的绝对路径,
         * 如为文字,则为具体文字
         */
        private String content;
        private Integer pdfPage;
        private String desc;
    }


    public static List<String> pdfPathToImagePaths(String pdfPath) throws IOException {
        log.info("pdfPathToImagePaths 将多页pdf转化为图片，pdf路径为："+pdfPath);
        File pdfFile = new File(pdfPath);
        String name = pdfFile.getName();
        String fileName = name.substring(0, name.indexOf("."));
        String pdfDir = pdfFile.getParent() + File.separator + fileName + "-image";
        File pdfDirFile = new File(pdfDir);
        List<String> imagePathList =new ArrayList<>();
        if(pdfDirFile.exists() && pdfDirFile.isDirectory()){
            File[] listFiles = pdfDirFile.listFiles();
            if(listFiles != null){
                for(int i=0,l=listFiles.length;i<l;i++){
                    log.info("pdfPathToImagePaths 目录{}下第{}张的图片路径为：{}", pdfDir, i ,listFiles[i].getAbsolutePath());
                    imagePathList.add(listFiles[i].getAbsolutePath());
                }
                return imagePathList;
            }
        }
        pdfDirFile.mkdirs();
        PDDocument pdDocument = PDDocument.load(pdfFile);
        int pageCount = pdDocument.getNumberOfPages();
        PDFRenderer pdfRenderer = new PDFRenderer(pdDocument);
        for (int pageIndex=0; pageIndex<pageCount; pageIndex++) {
            String imgPath = pdfDir + File.separator +pageIndex+".jpg";
            BufferedImage image = pdfRenderer.renderImageWithDPI(pageIndex, 105, ImageType.RGB);
            ImageIO.write(image, "jpg", new File(imgPath));
            imagePathList.add(imgPath);
            log.info("pdfPathToImagePaths 第{}张生成的图片路径为：{}",pageIndex,imgPath);
        }
        pdDocument.close();
        return imagePathList;
    }
}
